/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
import { defineComponent, ref, SetupContext, watch } from "vue";
import { useCompare } from "../../composition/use-compare";
import { KeyCode, useEvent } from "../../composition/use-event";
import { DateObject, Period } from "../../types/common";
import { YearViewItem } from "../../types/year";
import { yearProps, YearPropsType } from "./year.props";

export default defineComponent({
    name: 'FDatePickerYearView',
    props: yearProps,
    emits: ['click', 'keyDown', 'mouseEnter', 'mouseLeave'] as (string[] & ThisType<void>) | undefined,
    setup(props: YearPropsType, context: SetupContext) {
        const years = ref<YearViewItem[][]>(props.years);
        const enableMarkCurrent = ref(props.enableMarkCurrent);
        const enableKeyboadNavigate = ref(props.enableKeyboadNavigate);
        const enablePeriod = ref(props.enablePeriod);
        const selectedYear = ref<DateObject | null>(props.selected);
        const selectedYearPeriod = ref<Period | null>(props.selectedPeriod);

        const { equal, inPeriod, isInitializedDate, equalOrEarlier } = useCompare();
        const { getKeyCodeFromEvent } = useEvent();

        watch(() => props.years, () => {
            years.value = props.years;
        });
        watch(() => props.selected, () => {
            selectedYear.value = props.selected;
        });

        const yearContainerClass = (rowIndex: number, yearIndex: number) => {
            const yearClassName = `y_${rowIndex}_${yearIndex}`;
            const classObject = {
                'f-datepicker-no-currmonth': (rowIndex === 0 && yearIndex === 0) || (rowIndex === 3 && yearIndex === 2),
            } as Record<string, boolean>;
            classObject[yearClassName] = true;
            return classObject;
        };

        function isYearInPeriod(year: DateObject): boolean {
            return inPeriod(year, selectedYearPeriod.value);
        }

        function isSelectedYear(year: DateObject): boolean {
            return !!selectedYear.value && equal({ year: selectedYear.value.year }, year);
        }

        function hasSameYearInPeriod(year: DateObject): boolean {
            return !!selectedYearPeriod.value && (
                equal({ year: selectedYearPeriod.value.from.year }, year) ||
                equal({ year: selectedYearPeriod.value.to.year }, year)
            );
        }

        const yearClass = (target: YearViewItem) => {
            const classObject = {
                'f-datepicker-year-cell': true,
                'f-datepicker-current': target.isCurrent && enableMarkCurrent.value,
                'f-datepicker-selected': (!selectedYearPeriod.value && isSelectedYear(target.date)) ||
                    (enablePeriod.value && hasSameYearInPeriod(target.date)),
                'f-datepicker-disabled': target.disable,
                'f-datepicker-range': isYearInPeriod(target.date) || target.range
            } as Record<string, boolean>;
            return classObject;
        };

        function onClickYear($event: Event, yearViewItem: YearViewItem) {
            $event.stopPropagation();
            if (yearViewItem.disable) {
                return;
            }
            context.emit('click', yearViewItem);
        }

        function onKeyDown($event: KeyboardEvent, yearViewItem: YearViewItem) {
            const keyCode: number = getKeyCodeFromEvent($event);
            if (keyCode !== KeyCode.tab) {
                $event.preventDefault();

                if (keyCode === KeyCode.enter || keyCode === KeyCode.space) {
                    onClickYear($event, yearViewItem);
                } else if (enableKeyboadNavigate.value) {
                    context.emit('keyDown', yearViewItem);
                }
            }
        }

        function onMouseEnter(target: YearViewItem) {
            if (selectedYearPeriod.value && isInitializedDate(selectedYearPeriod.value.from) &&
                !isInitializedDate(selectedYearPeriod.value.to)
            ) {
                years.value.forEach((row: YearViewItem[]) => {
                    row.forEach((item: YearViewItem) => {
                        item.range = !!selectedYearPeriod.value &&
                            (
                                (equalOrEarlier(selectedYearPeriod.value.from, item.date) && equalOrEarlier(item.date, target.date)) ||
                                (equalOrEarlier(item.date, selectedYearPeriod.value.from) && equalOrEarlier(target.date, item.date))
                            );
                    });
                });
                context.emit('mouseEnter', target);
            }
        }

        function onMouseLeave() {
            years.value.forEach((row: YearViewItem[]) => {
                row.forEach((item: YearViewItem) => {
                    item.range = false;
                });
            });
            context.emit('mouseLeave');
        }

        return () => {
            return (
                <table class="f-datepicker-table-wrapper">
                    <tbody class="f-datepicker-table">
                        {years.value && years.value.map((row: YearViewItem[], rowIndex: number) => {
                            return (
                                <tr>
                                    {row.map((yearViewItem: YearViewItem, index: number) => {
                                        return (
                                            <td id={`y_{yi}_{i}`} class={yearContainerClass(rowIndex, index)}
                                                onClick={(payload: MouseEvent) => onClickYear(payload, yearViewItem)}
                                                onKeydown={(payload: KeyboardEvent) => onKeyDown(payload, yearViewItem)}
                                                onMouseenter={() => onMouseEnter(yearViewItem)}
                                                onMouseleave={() => onMouseLeave()}
                                                tabindex="0" >
                                                <div class="f-datepicker-year">
                                                    <span class={yearClass(yearViewItem)} >{yearViewItem.year}</span >
                                                </div>
                                            </td>
                                        );
                                    })}
                                </tr>
                            );
                        })}
                    </tbody >
                </table >
            );
        };
    }
});
